
class ResLoader {
    private static _inst: ResLoader = null;
    public static getInst(): ResLoader {
        if (!ResLoader._inst) {
            ResLoader._inst = new ResLoader();
        }
        return ResLoader._inst;
    }

    public load() {
        if (arguments.length === 0) {
            cc.error(`ResLoader load params must not be null`);
            return
        }
        let args = Array.from(arguments);
        let bundleName = args[0] || 'resources';
        args.splice(0, 1)
        this.loadBundle(bundleName, (bundle) => {
            bundle.load.apply(bundle, args);
        })
    }

    /**
     * 同步加载资源
     * @param bundleName bundle路径
     * @param path bundle内部资源路径
     * @param type 资源类型
     * @returns 
     */
     public loadSync(bundleName = 'resources', path, type?: typeof cc.Asset){
        return new Promise((resolve, reject) => {
            this.loadBundle(bundleName, (bundle) => {
                if (!bundle) {
                    reject(null);
                    return;
                }
                bundle.load(path, type, (err, asset: cc.Asset) => {
                    if (err) {
                        reject(`不存在资源 ==> ${bundleName}/${path}`);
                    }
                    else {
                        resolve(asset);
                    }
                })
            })
        }).catch(err => {
            console.log(err);
        })
    }

    /** 
     * 加载Bundle
     * @param bundleName bundle路径
     * @param cb 回调
     */
    public loadBundle(bundleName: string, cb?: (bundle: cc.AssetManager.Bundle) => void) {
        let bundle = cc.assetManager.getBundle(bundleName);
        if (bundle) {
            cb && cb(bundle);
        }
        else {
            cc.assetManager.loadBundle(bundleName, (err, b:cc.AssetManager.Bundle) => {
                if (err) {
                    cb && cb(null);
                    cc.error(err);
                }
                else {
                    cb && cb(b);
                }
            })
        }
    }

    /**
     * 同步加载bundle
     * @param bundleName bundle路径
     * @returns 
     */
    public loadBundleSync(bundleName: string) { 
        return new Promise((resolve, reject) => {
            let bundle = cc.assetManager.getBundle(bundleName);
            if (bundle) {
                resolve(bundle);
            }
            else {
                cc.assetManager.loadBundle(bundleName, (err, b:cc.AssetManager.Bundle) => {
                    if (err) {
                        reject(null);
                        cc.error(err);
                    }
                    else {
                        resolve(b);
                    }
                })
            }
        }).catch(err => {
            console.log(err);
        })
    }

    /** 加载文件夹 */
    public loadDirSync(bundleName: string, path: string, type?: typeof cc.Asset) {
        return new Promise((resolve, reject) => {
            this.loadBundle(bundleName, (bundle) => {
                bundle.loadDir(path, type, (err, asset) => {
                    if (err) {
                        reject(null);
                        cc.error(err);
                    }
                    else {
                        resolve(asset);
                    }
                })
            })
        }).catch(err => {
            console.log(err);
        })
    }

    /**
     * 移除Bundle
     * @param bundle bundle路径或者实例
     * @param removeAssets 是否释放bundle内的资源
     */
    public removeBundle(bundle: string | cc.AssetManager.Bundle, removeAssets = false) {
        if (typeof bundle === 'string') {
            bundle = cc.assetManager.getBundle(bundle);
        }
        if (!bundle) {
            cc.error('bundle not find');
            return;
        }
        if (removeAssets) {
            bundle.releaseAll();
        }
        cc.assetManager.removeBundle(bundle);
    }
}
export default ResLoader.getInst();